#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri Nov  9 20:55:55 2018

@author: tywin
第二章 2.1 kNN分类算法
"""

import kNN
from numpy import *
import operator

group,labels = kNN.createDataset()

#可以得出4组数据，每组数据都有明确的属性或者特征值
print(labels,group)

#kNN核心算法
#用于分类的输入向量inX
#dataSet 训练样本集
#labels 标签向量
#k 最近邻居数目
def classify0(inX, dataSet, labels, k):
    dataSetSize = dataSet.shape[0]
    #
    #函数形式： tile(A，rep)
    #功能：重复A的各个维度
    #参数类型：
    #- A: Array类的都可以
    #- rep：A沿着各个维度重复的次数
    #
    diffMat = tile(inX, (dataSetSize, 1)) - dataSet
    sqDifMat = diffMat**2
    sqDistances = sqDifMat.sum(axis=1)
    distances = sqDistances**0.5
    #发现argsort()函数是将x中的元素从小到大排列，提取其对应的index(索引)，然后输出到y
    sortedDistIndicies = distances.argsort()
    classCount={}
    
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
    
    #items函数，将一个字典以列表的形式返回，因为字典是无序的，所以返回的列表也是无序的。
    #operator模块提供的itemgetter函数用于获取对象的哪些维的数据，参数为一些序号
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1),reverse=True)
    print(sortedClassCount)
    return sortedClassCount[0][0]
    
    
    
print(classify0([0,0],group, labels, 3))

'''
使用kNN算法改进约会网站的配对效果
'''
#读取文件
datingDataMat,datingLabels = kNN.file2Matrix('datingTestSet2.txt')
print(datingDataMat,datingLabels)

#绘制原始数据散点图
import matplotlib
import matplotlib.pyplot as plt
fig = plt.figure()
plt.xlabel("每周消费的冰激凌公升数",fontproperties='SimHei',fontsize=14)
plt.ylabel("玩视频游戏所耗时间百分比",fontproperties='SimHei',fontsize=14)
ax = fig.add_subplot(111)
#将datingDataMat的第二列第三列属性展示数据，发现区分不明显
ax.scatter(datingDataMat[:,1],datingDataMat[:,2],15.0*array(datingLabels),15.0*array(datingLabels))
#plt.show()

#将datingDataMat第一列和第二列用散点图展示
plt.xlabel("玩视频游戏所耗时间百分比",fontproperties='SimHei',fontsize=14)
plt.ylabel("每年获取的飞行常客里程数",fontproperties='SimHei',fontsize=14)
ax.scatter(datingDataMat[:,0],datingDataMat[:,1],15.0*array(datingLabels),15.0*array(datingLabels))
plt.show()

#测试归一化处理方法
normMat,ranges,minVals = kNN.autoNorm(datingDataMat)


#测试算法
def datingClassTest():
    hotRatio = 0.10
    datingDataMat,datingLabels = kNN.file2Matrix('datingTestSet2.txt')
    normMat, ranges, minVals = kNN.autoNorm(datingDataMat)
    m = normMat.shape[0]
    numTestVecs = int(m*hotRatio)
    errorCount = 0.0
    
    for i in range(numTestVecs):
        classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
        
        print('the classifier came back with:%d, the real answer is :%d'%(classifierResult,datingLabels[i]))
        
        if (classifierResult != datingLabels[i]):
            errorCount += 1.0
    print('the total error rate is:%f'%(errorCount/float(numTestVecs)))
    
datingClassTest()


##
##    构建完整可用系统
##
def classifyPerson():
    resultList = ['not at all','in small doses','in large doses']
    
    #从输入源获取数据 input()
    percentTats = float(input('percentage of time spent playing video game?'))
    ffMiles = float(input('frequent flier miles earned per year?'))
    iceCream = float(input('liter of ice cream consumed per year?'))
    
    datingDataMat,datingLabels = kNN.file2Matrix('datingTestSet2.txt')
    normMat, ranges, minVals = kNN.autoNorm(datingDataMat)
    inArr = array([ffMiles, percentTats, iceCream])
    
    classifierResult = classify0((inArr-minVals)/ranges,normMat,datingLabels,3)
    
    print('U will probably like this person:',resultList[classifierResult - 1])

#print("开始预测------->")
#classifyPerson()


'''
手写数字识别
'''

#testVect = kNN.img2vector('digits/testDigits/0_13.txt')
#print('--------testVect-----------')
#print(testVect)


import os, sys

def handwritingClassTest():
    hwLabels = []
    #获取训练数据目录名
    trainingFileList = os.listdir('digits/trainingDigits')
    m = len(trainingFileList)
    trainingMat = zeros((m,1024))
    for i in range(m):
        fileNameStr = trainingFileList[i]
        fileString = fileNameStr.split('.')[0]
        #从文件名解析分类数字
        classNumStr = int(fileString.split('_')[0])
        hwLabels.append(classNumStr)
        trainingMat[i,:] = kNN.img2vector('digits/trainingDigits/%s'%fileNameStr)
    
    testFileList = os.listdir('digits/testDigits')
    errorCount = 0.0
    mTest = len(testFileList)
    for i in range(mTest):
        fileNameStr = testFileList[i]
        fileString = fileNameStr.split('.')[0]
        classNumStr = int(fileString.split('_')[0])
        vectorUnderTest = kNN.img2vector('digits/testDigits/%s'%fileNameStr)
        classifierResult = classify0(vectorUnderTest,trainingMat,hwLabels,3)
        print('the classifier came back with:%d, the real answer is %s'%(classifierResult,classNumStr))
        if(classifierResult != classNumStr):
            errorCount += 1.0
            
    print("错误预测总数为%s"%errorCount)
    print('错误率为%s'%(errorCount/float(mTest)))
        
        
handwritingClassTest()
        